package dj.common.support;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Optional;

/**
 * <br>
 * <p>
 * - 重写RequestMapping使之具备path传递性
 * </p>
 *
 * <br>
 *
 * @author ZJG
 * @version 1.0
 * @date 2021/11/12 上午10:26
 */
@Slf4j
public class ControllerRequestMapping extends RequestMappingHandlerMapping {

    private static final Map<String, RequestMappingInfo> mappingMap = Maps.newConcurrentMap();
    /**
     * 是否打印mapping
     */
    private boolean logMappingPath = true;

    public ControllerRequestMapping(boolean logMappingPath) {
        this.logMappingPath = logMappingPath;
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo mappingInfo = super.getMappingForMethod(method, handlerType);
        Class<?> superClass = handlerType.getSuperclass();
        mappingInfo = appendParentRequestMapping(superClass,mappingInfo);
        logMapping(mappingInfo);
        return mappingInfo;
    }

    /**
     * 追加父类mapping
     * @param handlerType
     * @param mappingInfo
     * @return
     */
    protected RequestMappingInfo appendParentRequestMapping(Class<?> handlerType,RequestMappingInfo mappingInfo) {
        if(handlerType==null) {
            return mappingInfo;
        }
        Optional<String> first = ObjectUtil.isNull(mappingInfo)? null: mappingInfo.getPatternsCondition().getPatterns().stream().findFirst();
        RequestMapping parentRequestMapping = handlerType.getAnnotation(RequestMapping.class);
        if(ObjectUtil.isNotNull(parentRequestMapping)
                && parentRequestMapping.value().length > 0
                && ObjectUtil.isNotNull(mappingInfo)
                && (ObjectUtil.isNotEmpty(first)
                        && first.isPresent()
                        && !StrUtil.containsAny(first.get(), parentRequestMapping.value()))) {
            //使用path工具向前追加supper class path
            mappingInfo = RequestMappingInfo.paths(parentRequestMapping.value()).build().combine(mappingInfo);
        }
        return appendParentRequestMapping(handlerType.getSuperclass(),mappingInfo);
    }

    /**
     * Override spring boot2不打印mapping path
     * @param info
     */
    private void logMapping(RequestMappingInfo info) {
        if(!logMappingPath || info==null) {
            return;
        }
        Optional<String> first = info.getPatternsCondition().getPatterns().stream().findFirst();
        if (ObjectUtil.isNotEmpty(first)
                && first.isPresent()
                && ObjectUtil.isNotNull(mappingMap.get(first.get()))) {
            return;
        }
        mappingMap.put(first.get(), info);
        log.info("mapping path: {}", info.toString());
    }

}
